#!/bin/bash
###############################################################################
#       脚本名称: log_async.sh
#       功能描述: 异步日志处理模块,实现后台异步写入提升性能。
#       作者: 林再来
#       日期: 2025-10-14
#       版本: 1.0
#       功能:
#           1、后台异步写入队列
#           2、非阻塞日志记录
#           3、批量异步刷新
#           4、优雅关闭和强制刷新
#           5、异步任务状态监控
#       依赖(插件/命令):
#           无
###############################################################################

# 防止重复加载
[[ -n "${_LOG_ASYNC_LOADED:-}" ]] && return 0
readonly _LOG_ASYNC_LOADED=1

#-----------------------------------------------------------------------------
# 全局变量
#-----------------------------------------------------------------------------
# 异步队列文件路径(使用临时文件)
declare -gA _LOG_ASYNC_QUEUE_FILE
# 异步处理器进程ID
declare -gA _LOG_ASYNC_WORKER_PID
# 异步模式启用标志
declare -g _LOG_ASYNC_ENABLED="false"
# 异步队列最大大小
declare -gA _LOG_ASYNC_QUEUE_MAX_SIZE
# 异步刷新间隔
declare -gA _LOG_ASYNC_FLUSH_INTERVAL

#-----------------------------------------------------------------------------
# 默认配置（参考config模块的做法，先检查是否已定义）
#-----------------------------------------------------------------------------
if [[ -z "${DEFAULT_ASYNC_QUEUE_SIZE:-}" ]]; then
    readonly DEFAULT_ASYNC_QUEUE_SIZE=1000
fi
if [[ -z "${DEFAULT_ASYNC_FLUSH_INTERVAL:-}" ]]; then
    readonly DEFAULT_ASYNC_FLUSH_INTERVAL=1
fi

#-----------------------------------------------------------------------------
# 函数: 初始化异步处理
# 参数: $1 - appender名称
#       $2 - 队列大小(可选,默认1000)
#       $3 - 刷新间隔/秒(可选,默认1)
# 返回: 0-成功, 1-失败
#-----------------------------------------------------------------------------
function _log_async_init() {
    local appender_name="$1"
    local queue_size="${2:-$DEFAULT_ASYNC_QUEUE_SIZE}"
    local flush_interval="${3:-$DEFAULT_ASYNC_FLUSH_INTERVAL}"
    
    # 创建临时队列文件
    local queue_file=$(mktemp -t "log_async_${appender_name}_XXXXXX")
    _LOG_ASYNC_QUEUE_FILE["$appender_name"]="$queue_file"
    _LOG_ASYNC_QUEUE_MAX_SIZE["$appender_name"]="$queue_size"
    _LOG_ASYNC_FLUSH_INTERVAL["$appender_name"]="$flush_interval"
    
    # 启动后台工作进程
    _log_async_start_worker "$appender_name" &
    _LOG_ASYNC_WORKER_PID["$appender_name"]=$!
    
    # 注意：不在库脚本中使用 trap EXIT，避免影响交互式 shell
    # 用户如需清理异步工作进程，可在主执行脚本中显式调用 log_async_shutdown_all
    # trap "_log_async_shutdown_all" EXIT INT TERM  # ← 已禁用
    
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 启动异步工作进程
# 参数: $1 - appender名称
# 返回: 不返回(后台运行)
#-----------------------------------------------------------------------------
function _log_async_start_worker() {
    local appender_name="$1"
    local queue_file="${_LOG_ASYNC_QUEUE_FILE[$appender_name]}"
    local flush_interval="${_LOG_ASYNC_FLUSH_INTERVAL[$appender_name]}"
    
    # 后台循环处理队列
    while true; do
        # 检查队列文件是否存在
        if [[ ! -f "$queue_file" ]]; then
            break
        fi
        
        # 读取队列内容并处理
        if [[ -s "$queue_file" ]]; then
            # 创建临时文件存储队列内容
            local temp_file="${queue_file}.processing"
            
            # 原子性地移动队列文件
            mv "$queue_file" "$temp_file" 2>/dev/null
            touch "$queue_file"
            
            # 处理日志(这里简化为直接输出,实际应调用appender)
            if [[ -f "$temp_file" ]]; then
                cat "$temp_file" >&2
                rm -f "$temp_file"
            fi
        fi
        
        # 等待刷新间隔
        sleep "$flush_interval"
    done
}

#-----------------------------------------------------------------------------
# 函数: 异步写入日志
# 参数: $1 - appender名称
#       $2 - 日志内容
# 返回: 0-成功, 1-失败
#-----------------------------------------------------------------------------
function _log_async_write() {
    local appender_name="$1"
    local log_content="$2"
    
    local queue_file="${_LOG_ASYNC_QUEUE_FILE[$appender_name]}"
    
    # 检查队列文件是否存在
    if [[ ! -f "$queue_file" ]]; then
        echo "错误: 异步队列未初始化: $appender_name" >&2
        return 1
    fi
    
    # 非阻塞写入队列(使用文件锁)
    (
        flock -n 200 || exit 1
        echo "$log_content" >> "$queue_file"
    ) 200>"${queue_file}.lock" 2>/dev/null
    
    local ret=$?
    
    # 检查队列大小,如果超出限制则触发同步刷新
    local queue_size="${_LOG_ASYNC_QUEUE_MAX_SIZE[$appender_name]}"
    local current_size=$(wc -l < "$queue_file" 2>/dev/null || echo 0)
    
    if [[ $current_size -ge $queue_size ]]; then
        # 队列满,触发立即刷新
        _log_async_flush "$appender_name"
    fi
    
    return $ret
}

#-----------------------------------------------------------------------------
# 函数: 手动刷新异步队列
# 参数: $1 - appender名称
# 返回: 0-成功
#-----------------------------------------------------------------------------
function _log_async_flush() {
    local appender_name="$1"
    local queue_file="${_LOG_ASYNC_QUEUE_FILE[$appender_name]}"
    
    # 等待工作进程处理完当前批次
    sleep 0.1
    
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 停止异步处理
# 参数: $1 - appender名称
# 返回: 0-成功
#-----------------------------------------------------------------------------
function _log_async_shutdown() {
    local appender_name="$1"
    local worker_pid="${_LOG_ASYNC_WORKER_PID[$appender_name]}"
    local queue_file="${_LOG_ASYNC_QUEUE_FILE[$appender_name]}"
    
    # 刷新剩余日志
    _log_async_flush "$appender_name"
    
    # 停止工作进程
    if [[ -n "$worker_pid" ]] && kill -0 "$worker_pid" 2>/dev/null; then
        kill "$worker_pid" 2>/dev/null
        wait "$worker_pid" 2>/dev/null
    fi
    
    # 清理队列文件
    if [[ -f "$queue_file" ]]; then
        # 处理剩余日志
        if [[ -s "$queue_file" ]]; then
            cat "$queue_file" >&2
        fi
        rm -f "$queue_file" "${queue_file}.lock"
    fi
    
    unset _LOG_ASYNC_WORKER_PID["$appender_name"]
    unset _LOG_ASYNC_QUEUE_FILE["$appender_name"]
    
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 停止所有异步处理
# 参数: 无
# 返回: 0-成功
#-----------------------------------------------------------------------------
function _log_async_shutdown_all() {
    for appender_name in "${!_LOG_ASYNC_WORKER_PID[@]}"; do
        _log_async_shutdown "$appender_name"
    done
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 启用异步模式
# 参数: 无
# 返回: 0-成功
#-----------------------------------------------------------------------------
function log_async_enable() {
    _LOG_ASYNC_ENABLED="true"
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 禁用异步模式
# 参数: 无
# 返回: 0-成功
#-----------------------------------------------------------------------------
function log_async_disable() {
    _LOG_ASYNC_ENABLED="false"
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 检查异步模式是否启用
# 参数: 无
# 返回: 0-已启用, 1-未启用
#-----------------------------------------------------------------------------
function log_async_is_enabled() {
    [[ "$_LOG_ASYNC_ENABLED" == "true" ]]
}

#-----------------------------------------------------------------------------
# 函数: 获取异步队列状态
# 参数: $1 - appender名称
# 返回: 输出状态信息
#-----------------------------------------------------------------------------
function _log_async_status() {
    local appender_name="$1"
    local queue_file="${_LOG_ASYNC_QUEUE_FILE[$appender_name]}"
    local worker_pid="${_LOG_ASYNC_WORKER_PID[$appender_name]}"
    local queue_size="${_LOG_ASYNC_QUEUE_MAX_SIZE[$appender_name]}"
    local flush_interval="${_LOG_ASYNC_FLUSH_INTERVAL[$appender_name]}"
    
    local current_size=0
    if [[ -f "$queue_file" ]]; then
        current_size=$(wc -l < "$queue_file" 2>/dev/null || echo 0)
    fi
    
    local worker_status="停止"
    if [[ -n "$worker_pid" ]] && kill -0 "$worker_pid" 2>/dev/null; then
        worker_status="运行中"
    fi
    
    echo "Async Queue: $appender_name"
    echo "  工作进程: $worker_status (PID: ${worker_pid:-N/A})"
    echo "  队列大小: $current_size / $queue_size"
    echo "  刷新间隔: ${flush_interval}秒"
    echo "  队列文件: $queue_file"
}

#-----------------------------------------------------------------------------
# 测试函数
#-----------------------------------------------------------------------------
function _log_async_test() {
    echo "=== 异步日志处理模块测试 ==="
    
    echo ""
    echo "1. 初始化异步处理:"
    _log_async_init "test_async" 10 2
    echo "  ✓ 初始化成功"
    
    echo ""
    echo "2. 异步写入日志:"
    for i in {1..5}; do
        _log_async_write "test_async" "[INFO] 异步日志 $i"
        echo "  写入第${i}条"
    done
    
    echo ""
    echo "3. 查看异步队列状态:"
    _log_async_status "test_async" | sed 's/^/  /'
    
    echo ""
    echo "4. 等待后台处理(5秒):"
    sleep 5
    
    echo ""
    echo "5. 再次查看状态:"
    _log_async_status "test_async" | sed 's/^/  /'
    
    echo ""
    echo "6. 停止异步处理:"
    _log_async_shutdown "test_async"
    echo "  ✓ 停止成功"
}

# 如果直接执行此脚本,运行测试
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    _log_async_test
fi

